#include "QGpsParser.h"
#include <qextserialport.h>
#include "QNmea0183Package.h"
#include <QDebug>

QGpsParser::QGpsParser(QObject *parent) :
    QObject(parent),
    _commPort(NULL)
{
}

QGpsParser::~QGpsParser()
{
    stop();
}

void QGpsParser::start(const QString &commName)
{
    if(isValid())
        stop();

    _lastRecvedData.clear();
    _commPort = new QextSerialPort(commName, QextSerialPort::EventDriven);
    _commPort->setBaudRate(BAUD9600);
    _commPort->setFlowControl(FLOW_OFF);

    if(_commPort->open(QIODevice::ReadWrite))
    {
        connect(_commPort, SIGNAL(readyRead()), this, SLOT(onCommPortDataReady()));
    }
    else
    {
        delete _commPort;
        _commPort = NULL;
    }
}

void QGpsParser::stop()
{
    if(!isValid())
        return;
    _commPort->close();
    _commPort->disconnect();
    delete _commPort;
    _commPort = NULL;
}

bool QGpsParser::isValid() const
{
    return ((_commPort != NULL) && _commPort->isOpen());
}

void QGpsParser::onCommPortDataReady()
{
    QByteArray bytes;
    int a = _commPort->bytesAvailable();
    bytes.resize(a);
    char *p = bytes.data();
    int len = bytes.size();
    _commPort->read(p, len);
    for(int i = 0; i < len; i++)
    {
        char ch = *p++;
        _lastRecvedData.append(ch);
        if(ch == '\n')
        {
            // Recved a Full Package
            QNmea0183Package pkg(_lastRecvedData);
            switch(pkg.type())
            {
            case QNmea0183Package::GGA:
                // position(latitude, longitude, altitude)
                gotGGAPackage(pkg);
                break;
            case QNmea0183Package::GSA:
                break;
            case QNmea0183Package::GSV:
                // satellites list
                gotGSVPackage(pkg);
                break;
            case QNmea0183Package::RMC:
                // utcTime & speed
                gotRMCPackage(pkg);
                break;
            default:
                break;
            }
            _lastRecvedData.clear();
        }
    }
}

void QGpsParser::gotRMCPackage(const QNmea0183Package &pkg)
{
    const RMCPackage &rmc = pkg.rmcInformation();
    if(rmc.flag != 'A')
        return;
    QDate d(rmc.utcDate.year,
            rmc.utcDate.month,
            rmc.utcDate.day);
    QTime t(rmc.utcTime.hour,
            rmc.utcTime.minute,
            rmc.utcTime.second,
            rmc.utcTime.msecond);
    QDateTime dt(d, t, Qt::UTC);
    emit utcTimeChanged(dt.toLocalTime());
    emit speedChanged(rmc.speed, rmc.speed * 1.852, rmc.direction);
}

void QGpsParser::gotGGAPackage(const QNmea0183Package &pkg)
{
    const GGAPackage &gga = pkg.ggaInformation();
    if(gga.flag == 0)
        return;
    emit positionChanged(gga.latitude, gga.nsFlag,
                     gga.longitude, gga.ewFlag,
                     gga.radioAltitude,
                     gga.rawLatitude, gga.rawLongitude);
}

void QGpsParser::gotGSVPackage(const QNmea0183Package &pkg)
{
    const GSVPackage &gsv = pkg.gsvInformation();
    if(_lastRecvedData.startsWith("$BD"))
    {
        if(gsv.msgIndex == 1)
            _bdSatelliteList.clear();
        for(int i = 0; i < 4; i++)
        {
            if(_bdSatelliteList.count() >= gsv.satelliteNum)
                break;
            _bdSatelliteList.append(gsv.satellites[i]);
        }
        if((gsv.msgCount == gsv.msgIndex)
                || (_bdSatelliteList.count() >= gsv.satelliteNum))
            emit BeiDouSatellites(_bdSatelliteList);
    }
    else if(_lastRecvedData.startsWith("$GP"))
    {
        if(gsv.msgIndex == 1)
            _gpSatelliteList.clear();
        for(int i = 0; i < 4; i++)
        {
            if(_gpSatelliteList.count() >= gsv.satelliteNum)
                break;
            _gpSatelliteList.append(gsv.satellites[i]);
        }
        if((gsv.msgCount == gsv.msgIndex)
                || (_gpSatelliteList.count() >= gsv.satelliteNum))
            emit GPSSatellites(_gpSatelliteList);
    }
}
